
#region Imported Namespaces
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

//using PHSRAG.Insight21.Common.SearchSupport;
using PHSRAG.Insight21.Admin;
using Annunciator = PHSRAG.WebControls.Annunciator;
using ActivityIndicator = PHSRAG.WebControls.ActivityIndicator;
using CommonSearchContext = PHSRAG.Insight21.SearchContext.CommonSearchContext;
using DataAccess = PHSRAG.Utility.DataAccess;
using AdminOrgTree = PHSRAG.Insight21.InsightWebControls.OrgTree;
using SearchCriteria = PHSRAG.Insight21.SearchContext.SearchCriteria;
using UserContext = PHSRAG.Insight21.Context.UserContext;
using Policy = PHSRAG.Insight21.Policy;
#endregion

namespace PHSRAG.Insight21.Admin.Controls
{
	/// <summary>
	/// </summary>
	public partial class OrgAccessCOSPicker : System.Web.UI.UserControl 
	{

		#region Constants
		private const string ClientScriptKey = "clientScriptKey_9B6A61D9-37E0-4bd5-A03E-0318B58955EA";
		private const string OrganizationListKey = "organizationList_9B6A61D9-37E0-4bd5-A03E-0318B58955EA";
		private const string PickerType = "COS";
        private const string JavascriptWindowTitle = "SetWindowTitle";
        #endregion

		#region Private Instance Variables
		private Policy.ICachePolicy	cachePolicy;
		private Policy.ICachePolicy	pageCachePolicy;
		#endregion

		#region Private Properties

		/// <summary>
		/// Gets the relevant user object from the cache if there is one otherwise loads 
		/// a new one based on the cached personID and cache's it.
		/// </summary>
		private User User
		{
			get
			{
				User user = cachePolicy.GetCachedObject(User.CacheKey) as Admin.User;

				Hashtable h = (Hashtable) pageCachePolicy.GetCachedObject(Keys.IncomingDataKey); 
				int personId = (int)h[Keys.PersonIdKey];
				if (user == null || (user.PersonId != personId))
				{
					user = new User(cachePolicy);
					user.Load(Utility.DataAccess.GetConnectionString(), personId);
					user.Cache();
				}

				return user;
			}
		}
		#endregion

		#region Event Handlers
		/// <summary>
		/// Handler for the close-button.
		/// </summary>
		/// <param name="sender">Button which raised the event</param>
		/// <param name="e">Argument associated with the event</param>
		protected void OnCloseWindow(object sender, System.EventArgs e)
		{
			string currentSelection = adminOrgTree.Selection;
			Hashtable currentSelectionMap = ConvertSelectionStringToHashtable(currentSelection);

			UserContext userContext = (UserContext)cachePolicy.GetCachedObject(UserContext.CacheKey);
			DataTable orgAccessTable = User.GetOrganizationRights(!userContext.IsKeyGiver? 0 : userContext.DomainUserId).OrganizationList.Copy();

			//remove rows that don't exist in the current Selection Map
			foreach (DataRow row in orgAccessTable.Rows)
			{
				if (!currentSelectionMap.ContainsKey(Convert.ToString((int)row["FwkDomainOrganizationId"])))
				{
					row.Delete();
				}
			}

			//add the selections that don't exist in the user's org access list already
			foreach (string key in currentSelectionMap.Keys)
			{
				bool keyIsRecursive = (((string)currentSelectionMap[key]).IndexOf("_AllChildren") > -1);
				DataRow[] rows = orgAccessTable.Select(string.Format("FwkDomainOrganizationId={0} AND IsRecursive={1}", key, keyIsRecursive));
				//if we don't have a row, add it...
				if (rows.Length == 0 ) 
				{
					DataRow row = orgAccessTable.NewRow();
					row["FwkDomainOrganizationId"] = key;
					row["IsRecursive"] = keyIsRecursive;
					row["FwkDomainUserId"] = User.DomainUserId;
					row["RightBitmask"] = 0;
					orgAccessTable.Rows.Add(row);
				}
			}
			

			User.GetOrganizationRights(!userContext.IsKeyGiver? 0 : userContext.DomainUserId).OrganizationList = orgAccessTable;

			SqlConnection connection = new SqlConnection(DataAccess.ConnectionString);			
			SqlTransaction transaction = null;
			try
			{
				connection.Open();
				transaction = connection.BeginTransaction("OrganizationAccessRights");
				User.GetOrganizationRights(!userContext.IsKeyGiver? 0 : userContext.DomainUserId).Save(transaction);
				User.UpdateUserResourceCache(transaction);
				transaction.Commit();
			}
			catch(Exception ex)
			{
				if(transaction != null)
					transaction.Rollback();

				annunciator.Message = ex.Message;
			}
			finally
			{
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}
			
			User.UnCache();
			Page.ClientScript.RegisterClientScriptBlock(GetType( ), ClientScriptKey, "<script language='javascript'>window.opener.document.location.href='../Admin/AdminUserAccessRights.aspx';window.close();</script>");
			cachePolicy.Cache(Keys.SaveEditStateKey, true); 
		}
		/// <summary>
		/// Handles for the control load event.
		/// </summary>
		/// <param name="sender">The entity which raised the event</param>
		/// <param name="e">Argument associated with the event</param>
		/// <remarks>
		/// Load the tree with organization information on non-postback.
		/// </remarks>

		protected void Page_Load(object sender, System.EventArgs e)
		{
			if (!IsPostBack)
				closeWindow.Text = "Save";
				LoadOrgTree();
		}
		
		#endregion

        #region Overrides
        /// <summary>
        /// Register clientside scripts.
        /// </summary>
        /// <param name="e">Argument associated with the event.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (!Page.ClientScript.IsClientScriptBlockRegistered(JavascriptWindowTitle))
            {
                string script =
                    "<script language=\"javascript\">\n" +
                    "\twindow.pageTitle.text = \"Organization Access Search\";\n" +
                    "</script>\n";

                Page.ClientScript.RegisterClientScriptBlock(GetType( ), JavascriptWindowTitle, script);
            }
        }
        #endregion

		#region Private Methods
		/// <summary>
		/// Convert the selection string (which may contain multiple COS selections) into a Hashtable. The key in the
		/// Hashtable is of the form "chiefCode-name", and the value is the org ID.
		/// </summary>
		/// <param name="selection">String of all '|' seaprated COS selections</param>
		/// <returns>Hashtable of sections</returns>
		private Hashtable ConvertSelectionStringToHashtable(string selection)
		{
			Hashtable hashtable = new Hashtable();
			string[] keyValueList = selection.Split('|');
			foreach (string keyValue in keyValueList)
			{
				Pair nameID = SplitSelection(keyValue);
				if (nameID != null)
					hashtable[nameID.Second] = nameID.First;
			}
			return hashtable;
		}

		/// <summary>
		/// Used to determine if the user is a System Administrator
		/// </summary>
		/// <param name="userContext">The user context information to be evaluated.</param>
		/// <returns>True if the user is a System Administrator otherwise False</returns>
		private bool IsUserSysAdmin(UserContext userContext)
		{
			return ((userContext.ModuleRoleBitmask & (int)Security.Enumerations.ModuleRoleBit.SystemAdministrator) != 0);
		}

		/// <summary>
		/// Get the organization information for the current user and bind that information to the org tree.
		/// If there is no orgranization to display, warn the user.
		/// </summary>
		private void LoadOrgTree()
		{
			Hashtable selectedOrgs = new Hashtable();

			UserContext userContext = (UserContext)cachePolicy.GetCachedObject(UserContext.CacheKey);
			//get the cached user's org access rights
			DataTable OrgTable = User.GetOrganizationRights(IsUserSysAdmin(userContext) ? 0 : (userContext.IsKeyGiver) ? userContext.DomainUserId : 0).OrganizationList;

			//get the logged in user's KeyGiverRights (if they are a sysadmin this table holds all orgs)
			DataTable pickerDataTable = userContext.KeyGiverRights;
			foreach (DataRow row in OrgTable.Rows)
			{
				//only add the item as selected if it exists in the key giver's list
				if (pickerDataTable.Select(String.Format("Id = {0}",row["FwkDomainOrganizationId"])).Length > 0)
				{
					if((bool)row["IsRecursive"])
					{
						//key is id plus special string for recursive rights
						StringBuilder sb = new StringBuilder();
						sb.Append(Convert.ToString(row["FwkDomainOrganizationId"]));
						sb.Append("_AllChildren");
						selectedOrgs.Add(sb.ToString(),String.Format("{0}-{1}{2}", row["ChiefCode"], row["Name"], "_AllChildren"));
					}
					else
					{
						//key is just id for non-recursive rights
						selectedOrgs.Add(Convert.ToString(row["FwkDomainOrganizationId"]),String.Format("{0}-{1}", row["ChiefCode"], row["Name"]));
					}
				}
			}

			if (selectedOrgs.Count > 0 )
				adminOrgTree.CurrentSelection = selectedOrgs;

			adminOrgTree.DataSource = pickerDataTable;

			if (pickerDataTable.Rows.Count == 0)
			{
				annunciator.Title = "Data Load Warning:";
				annunciator.Message = string.Format("No {0} data found matching the search criteria.", PickerType);
				annunciator.Visible = true;
			}
			else
			{
				DataTable orgInfo = cachePolicy.GetCachedObject(OrganizationListKey) as DataTable;
				if (orgInfo == null)
				{
					orgInfo = userContext.KeyGiverRights;
					cachePolicy.Cache(OrganizationListKey, orgInfo);
				}

				adminOrgTree.DataSource = new DataTable[]{pickerDataTable, orgInfo};

				annunciator.Title = "Note:";
				annunciator.Message = @"Selected organization(s) will be added to user's organization access rights.
					Deselected organization(s) will be removed from user's organization access rights.
					Click the Save button to save the user's organization access rights.";
				annunciator.Visible = true;
			}
		}

		/// <summary>
		/// Split the specified selection into a pair of values. The selection is of the form "name:id".
		/// </summary>
		/// <param name="selection">Selection string to split</param>
		/// <returns>Pair containing the name and ID</returns>
		private Pair SplitSelection(string selection)
		{
			Regex regex = new Regex(@"(?<name>[^:]+):(?<id>\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
			Match match = regex.Match(selection);
			if (match.Success)
				return new Pair(match.Groups["name"].Value, match.Groups["id"].Value);
			return null;
		}
		#endregion

		#region Web Form Designer generated code
		/// <summary>
		/// Handler for the page initialize event.
		/// </summary>
		/// <param name="e">Argument associated with the event</param>
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);

			pageCachePolicy = (Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey];
			cachePolicy = (Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey];
		}
		
		/// <summary>
		///		Required method for Designer support - do not modify
		///		the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
		}
		#endregion

	}
}

// --- EOF ---
